//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================


//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - S+S Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Windows.Forms;

using Microsoft.Practices.ObjectBuilder;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.EventBroker;
using Microsoft.Practices.SmartClient.DisconnectedAgent;
using Microsoft.Office.Interop.Excel;

using LitwareHR.Infrastructure.Interface;
//using LitwareHR.Recruiting.Contract;
using LitwareHR.PublicApp.WinUX.Constants;
using LitwareHR.PublicApp.WinUX.Services;
using LitwareHR.Infrastructure.Interface.Constants;

using Shp.Runtime.Contract;
using System.IO;
using LitwareHR.PublicApp.WinUX.ExcelImport;
using LitwareHR.PublicApp.WinUX.Entities;
using System.Globalization;

namespace LitwareHR.PublicApp.WinUX
{
    public partial class OpenPositionViewPresenter : Presenter<IOpenPositionView>
    {
        //Services this presenter uses
        private RecruitingService recruitingService = null;
        private RequestsManagerService requestsManagerService = null;

        //Used to store the definition of the Postion entity
        private EntityField[] positionFieldDef;
        
        PositionCollection validList = new PositionCollection();
        PositionCollection inValidList = new PositionCollection();
        PositionCollection queuedList = new PositionCollection();
        PositionCollection failedList = new PositionCollection();

        int positionIndex = -1;
        string positionType = string.Empty;

        #region EventSubscription
        [EventSubscription(EventTopicNames.MetaModelUpdating, ThreadOption.UserInterface)]
        public void OnMetaModelUpdating(object sender, EventArgs eventArgs)
        {
            View.StartSyncAnimation();
        }

        [EventSubscription(EventTopicNames.MetaModelUpdated, ThreadOption.UserInterface )]
        public void ModelUpdatedHandler(object sender, MetaModelUpdatedEventArgs e)
        {
            //Update the defintion of position
            positionFieldDef = recruitingService.GetPositionFields();
            View.SetupControls(positionFieldDef);
            View.NotifySchemaChanges();
            View.EndSyncAnimation();
        }

        [EventSubscription(EventTopicNames.DataSynchronizing, ThreadOption.UserInterface)]
        public void OnDataSynchronizing(object sender, EventArgs eventArgs)
        {
            View.StartSyncAnimation();
        }

        [EventSubscription(EventTopicNames.DataSynchronized, ThreadOption.UserInterface)]
        public void OnDataSynchronized(object sender, EventArgs eventArgs)
        {
            View.EndSyncAnimation();
        }
        #endregion
        

        /// <summary>
        /// Constructor. Notice injection of required services
        /// </summary>
        /// <param name="recruitingService"></param>
        /// <param name="requestsManagerService"></param>
        public OpenPositionViewPresenter([ServiceDependency] RecruitingService recruitingService,
                                         [ServiceDependency] RequestsManagerService requestsManagerService)
        {
            this.recruitingService = recruitingService;
            this.requestsManagerService = requestsManagerService;
        }
        
        /// <summary>
        /// This method is a placeholder that will be called by the view when it has been loaded.
        /// </summary>
        
        public override void OnViewReady()
        {
            base.OnViewReady();

            View.LoadResources();

            //Load the Fields based on the metadata
            positionFieldDef = recruitingService.GetPositionFields();
            View.SetupControls(positionFieldDef);
            
            LoadDeadLetterQueueItems();
            ProcessOutputQueue();

            UpdateViewLists();
        }

        /// <summary>
        /// Close the view
        /// </summary>
        public void OnCloseView()
        {
            base.CloseView();
            WorkItem.SmartParts.Remove(View);
            if (View is IDisposable)
                ((IDisposable)View).Dispose();
        }

        private void UpdateViewLists()
        {
            View.BindValidList(validList);
            View.BindInvalidList(inValidList);
            View.BindFailedList(failedList);
            View.BindQueuedList(queuedList);
        }
    
        public void OnSave(EntityField[] list)
        {
           recruitingService.OpenPosition(list);

           if (positionType.Equals("DeadQueue"))
           {
               IRequestQueue deadLetterQueue = requestsManagerService.DeadQueue;
               deadLetterQueue.Remove(deadLetterQueue.GetRequest(failedList[positionIndex].RequestId));
           }
           else if (positionType.Equals("InvalidQueue"))
               inValidList.RemoveAt(positionIndex);

           positionType = string.Empty;
           positionIndex = -1;
        }

        public void SaveValidPositions()
        {
            for (int i = 0; i < validList.Count; i++)
                recruitingService.OpenPosition(validList[i].Fields.ToArray());

            validList.Clear();
        }

        public void LoadDeadLetterQueueItems()
        {
            IRequestQueue deadLetterQueue = requestsManagerService.DeadQueue;
            IEnumerable<Request> deadRequests = deadLetterQueue.GetRequests("AddInstance");
            
            failedList.Clear();
            
            foreach (Request request in deadRequests)
            {
                EntityField[] list = (EntityField[])request.CallParameters[1];
                List<EntityField> entitySet = new List<EntityField>();
                entitySet.AddRange(list);
                Position pos = new Position(entitySet);
                pos.Message = "Dead queue record!";
                pos.PosType = "DeadQueue";
                pos.RequestId = request.RequestId;
                failedList.Add(pos);               
            }

            UpdateViewLists();
        }

        public void ProcessOutputQueue()
        {
            IRequestQueue requestQueue = requestsManagerService.RequestQueue;
            IEnumerable<Request> requests = requestQueue.GetRequests("AddInstance");

            queuedList.Clear();

            foreach( Request request in requests )
            {
                EntityField[] list = (EntityField[])request.CallParameters[1];
                List<EntityField> entitySet = new List<EntityField>();
                entitySet.AddRange(list);
                queuedList.Add(new Position(entitySet));
            }

            UpdateViewLists();
        }

        public void ProcessRows(List<String[]> rows, bool isExcel)
        {            
            String[] headerColumns = rows[0];
            Dictionary<Int16, EntityField> columns = new Dictionary<Int16, EntityField>();

            //Get mapping of column to header.
            for (Int16 i = 0; i < headerColumns.GetLength(0); i++)
                foreach (EntityField field in positionFieldDef)
                    if (field.Name.ToUpper(CultureInfo.InvariantCulture).Equals(headerColumns[i].ToUpper(CultureInfo.InvariantCulture)))
                        columns.Add(i, field);

            //Parse data and classify into valid and invalid data.
            for (int i = 1; i < rows.Count; i++)
            {
                string[] dataColumns = rows[i];
                List<EntityField> entitySet = new List<EntityField>();

                for (Int16 j = 0; j < headerColumns.GetLength(0); j++)
                {
                    if (columns.ContainsKey(j) && j < dataColumns.GetLength(0))
                    {
                        EntityField field = new EntityField();
                        field.Name = columns[j].Name;
                        field.TypeName = columns[j].TypeName;
                        field.TypeId = columns[j].TypeId;
                        field.Id = columns[j].Id;
                        field.IsShared = columns[j].IsShared;                        
                        if (isExcel && field.TypeName == "Date and time")
                        {
                            Double dt;
                            if (Double.TryParse(dataColumns[j], out dt))
                                field.Value = DateTime.FromOADate(dt).ToShortDateString();
                            else
                                field.Value = dataColumns[j];
                        }
                        else 
                            field.Value = dataColumns[j];
                        entitySet.Add(field);
                    }
                }

                //Check if this set is valid
                Position pos = new Position(entitySet, positionFieldDef);

                if (pos.IsValid)
                    validList.Add(pos);
                else
                {
                    pos.PosType = "InvalidQueue";
                    inValidList.Add(pos);
                }
            }   
        }

        [EventSubscription(EventTopicNames.RequestQueueChanged, ThreadOption.UserInterface)]
        public void OnRequestQueueChanged(object sender, EventArgs eventArgs)
        {
            //Update RequestQueue List + DeadQueuList. Call ReBind Data.
            LoadDeadLetterQueueItems();
            ProcessOutputQueue();
        }

        public void OpenExcelFileAndImport()
        {
            //Configure open file dialog box
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.FileName = "";
            dlg.DefaultExt = ".xls";
            dlg.Filter = "Excel Document |*.xls;*.xlsx";
            dlg.RestoreDirectory = true;

            if (dlg.ShowDialog() == DialogResult.OK)
            {
                List<String[]> valueList = ExcelImport.ExcelImport.Import(dlg.FileName);
                ProcessRows(valueList, true);
                UpdateViewLists();
            }
        }

        internal void ResetPositions()
        {
            positionType = string.Empty;
            positionIndex = 0;
        }

        internal void SetPosition(int index, string type)
        {
            this.positionIndex = index;
            this.positionType = type;
        }

        internal void OnValidatePosition(List<EntityField> entitySet)
        {
            View.ValidatePosition(entitySet, positionFieldDef);
        }
    }
}

